import random, pygame

from pygame.locals import *
from Block import Block
from Constants import *
from Errors import *
from Stack import Stack
#from CuteGod import animator

class World:
    def __init__(self, blockImages, shadowImages, xSize=5, ySize=5, zMax=3):
        self.xMax = xSize
        self.yMax = ySize
        self.shadowImages = shadowImages
        self.stacks = []
        self.actors = []
        self.houses = []
        self.viewX = VIEW_X_INIT
        self.viewY = VIEW_Y_INIT
        self.canvas = pygame.Surface((MAP_WIDTH, MAP_HEIGHT)).convert()
        self.canvas.fill((255,255,255))
        
        self.randomBlocks(xSize, ySize, zMax, blockImages)
        
        self.cursor = None

        self.fullRender(self.canvas)
        
    def addActor(self, actor, pos):
        self.actors[pos[X]][pos[Y]] = actor
        
    def moveActor(self, fromPos, toPos):
        actor = self.actors[fromPos[X]][fromPos[Y]]
        self.actors[fromPos[X]][fromPos[Y]] = None
        self.actors[toPos[X]][toPos[Y]] = actor
        self.updateRow(fromPos[X],fromPos[Y])
        self.updateRow(toPos[X],toPos[Y])
        
        
    def shortStack(self, images, x, y):
        self.stacks[x].append(Stack(x,y, self.shadowImages))
        
    def initGrid(self, grid, width, height):
        for x in xrange(width):
            grid.append([])
            for y in xrange(height):
                grid[x].append(None)
        
    def randomBlocks(self, xSize, ySize, zMax, blockImages):
        keys = blockImages.keys()
        keyCount = len(keys)
        
        self.initGrid(self.stacks, xSize, ySize)
        self.initGrid(self.actors, xSize, ySize)
        self.initGrid(self.houses, xSize, ySize)
        for x in xrange(xSize):
            for y in xrange(ySize):
                self.stacks[x][y] = Stack(x,y,self.shadowImages)
                for z in xrange(0, random.randint(Z_MIN, zMax)):
                    key = keys[random.randint(0, keyCount-1)]
                    self.stacks[x][y].dropBlock(Block(key, blockImages))

    def render(self, screen):    
        self.viewX = self.cursor.x * TILE_WIDTH - VIEW_WIDTH/2
        self.viewY = self.cursor.y * TILE_WIDTH - VIEW_HEIGHT/2
        if self.viewX < 0:
            self.viewX = 0
        if self.viewY < 0:
            self.viewY = 0
        self.viewRect = Rect(self.viewX, self.viewY, VIEW_WIDTH, VIEW_HEIGHT)
        
        screen.blit(self.canvas,(VIEW_X_OFFSET, VIEW_Y_OFFSET), self.viewRect)
        
    def update(self, x, y):
        renderX = x * TILE_WIDTH
        renderY = y * TILE_Y_SPACING
        adjacentHeights = self.getAdjacentHeights(x, y)
        self.stacks[x][y].update(adjacentHeights)
        self.stacks[x][y].render(self.canvas)
        renderPos = self.getRenderingCoords((x,y))
        if self.actors[x][y] != None:
            self.actors[x][y].render(self.canvas, renderPos)
        if self.houses[x][y] != None:
            self.houses[x][y].render(self.canvas)
    
    def getRenderingCoords(self, pos):
        renderX = pos[X] * TILE_WIDTH
        renderY = pos[Y] * TILE_Y_SPACING + (MAP_Z-self.stacks[pos[X]][pos[Y]].size()-1) * TILE_DEPTH
        return (renderX, renderY)
    
    def updateRow(self, x, yStart):
        for y in xrange(len(self.stacks[x])) :
            self.update(x,y)
            if y == self.cursor.y and x == self.cursor.x:
                self.cursor.render(self.canvas)
    
    def getAdjacentHeights(self, x, y):
        blocks = self.stacks
        adjacentHeights = []
        if y > 0 :
            if x > 0 :
                adjacentHeights.append(blocks[x-1][y-1].size()) 
            else:
                adjacentHeights.append(-1)
            adjacentHeights.append(blocks[x][y-1].size())
            if x+2 < len(blocks):
                adjacentHeights.append(blocks[x+1][y-1].size())
            else:
                adjacentHeights.append(-1)
        else:
            for i in xrange(3):
                adjacentHeights.append(-1)
        if x > 0 :
            adjacentHeights.append(blocks[x-1][y].size())
        else:
            adjacentHeights.append(-1)
        if x+2 < len(blocks):
            
            adjacentHeights.append(blocks[x+1][y].size())
        else:
            adjacentHeights.append(-1)
        if y+1 < len(blocks[x]):
            if x > 0 :
                adjacentHeights.append(blocks[x-1][y+1].size()) 
            else:
                adjacentHeights.append(-1)
            adjacentHeights.append(blocks[x][y+1].size())
            if x+1 < len(blocks):
                adjacentHeights.append(blocks[x+1][y+1].size())
            else:
                adjacentHeights.append(-1)
        else:
            for i in xrange(3):
                adjacentHeights.append(-1)
        return adjacentHeights
                
    def fullRender(self, screen):
        blocks = self.stacks
        #xMax = self.xMax
        #yMax = self.yMax
        for x in xrange(len(blocks)):
            for y in xrange(len(blocks[x])):
                    self.update(x,y)
                    blocks[x][y].render(screen)
    
    def grab(self,x,y):
        stack = self.stacks[x][y]
        if stack.size() > Z_MIN and stack.locked == False:
            block = stack.grabBlock()
            self.cursor.z = self.cursor.z - 1
            self.updateRow(x,y)
            # play grab animation
            return block
        else:
            return None
    
    def drop(self, selected, x, y):
        stack = self.stacks[x][y]
        if stack.locked == False:
            stack.dropBlock(selected)
            self.cursor.z = self.cursor.z + 1
            self.updateRow(x,y)
        else:
            return selected
        